package com.slipper.system.menu.service;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;

import com.slipper.common.util.StringUtil;
import com.slipper.system.api.menu.bo.MenuPrivilegeBO;
import com.slipper.system.menu.dao.MenuDao;
import com.slipper.system.role.service.RoleService;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import com.slipper.common.constants.Constants;
import com.slipper.system.api.menu.bo.MenuBO;
import com.slipper.common.transaction.ReadTransactional;
import com.slipper.common.transaction.WriteTransactional;
import com.slipper.common.util.Tool;

import java.util.*;

@Service
@ReadTransactional
public class MenuService {
    @Resource
    private MenuDao menuDao;
    @Resource
    private RoleService roleService;
    @Resource
    private MenuPrivilegeService menuPrivilegeService;
    
    public MenuBO queryBy(String id){
        MenuBO menuBO = menuDao.queryBy(id);
        MenuPrivilegeBO menuPrivilegeBO = new MenuPrivilegeBO();
        menuPrivilegeBO.setMenuId(id);
        menuBO.getPrivileges().addAll(menuPrivilegeService.queryList(menuPrivilegeBO));
        return menuBO;
    }
    
    public PageInfo<MenuBO> queryPage(MenuBO bo){
        PageHelper.startPage(bo.getPageNumber(), bo.getPageSize());
        return new PageInfo<>(menuDao.queryList(bo));
    }
    
    @WriteTransactional
    public Integer save(MenuBO bo){
        if (bo.getParentId() == null) {
            bo.setParentId(Constants.ROOT_ID);
        }
        
        int result;
        if (bo.getId() != null && !"".equals(bo.getId())) {
            result = menuDao.update(bo);
        } else {
            bo.setId(Tool.getUUID());
            result = menuDao.insert(bo);
        }

        menuPrivilegeService.save(bo.getId(), bo.getPrivileges());
        return result;
    }
    
    @WriteTransactional
    public Integer delete(MenuBO bo){
        if (!StringUtil.isBlank(bo.getId())) {
            menuPrivilegeService.deleteByMenuId(bo.getId());
        }
        if (bo.getIds() != null) {
            Arrays.stream(bo.getIds()).forEach(menuPrivilegeService::deleteByMenuId);
        }
        return menuDao.delete(bo);
    }
    
    public List<MenuBO> queryUserMenus(MenuBO bo) {
        String employeeId = bo.getEmployeeId();
        if (this.roleService.isSuperAdmin(employeeId)) {
            MenuBO menuBO = new MenuBO();
            menuBO.setValid(Constants.VALID);
            List<MenuBO> menuList = this.menuDao.queryList(menuBO);
            
            List<MenuPrivilegeBO> menuPrivilegeList = this.menuPrivilegeService.queryList(new MenuPrivilegeBO());
            this.fillPrivilege(menuList, menuPrivilegeList);
            return menuList;
        } else {
            MenuBO menuBO = new MenuBO();
            menuBO.setEmployeeId(employeeId);
            menuBO.setValid(Constants.VALID);
            List<MenuBO> menuList = this.menuDao.queryList(menuBO);
            
            // 加载父菜单
            Set<String> parentMenuIds = new HashSet<>();
            for (MenuBO menu : menuList) {
                if (parentMenuIds.add(menu.getParentId())) {
                    String parentId = menu.getParentId();
                    while(parentId != null && !"0".equals(parentId)) {
                        MenuBO parentMenu = this.menuDao.queryBy(menu.getParentId());
                        if (parentMenu.getParentId() != null) {
                            if (!parentMenuIds.add(parentMenu.getParentId())) {
                                break;
                            }
                        }
                        parentId = parentMenu.getParentId();
                    }
                }
            }
            if (!parentMenuIds.isEmpty()) {
                MenuBO qo = new MenuBO();
                qo.setIds(parentMenuIds.toArray(new String[] {}));
                List<MenuBO> parentMenuList = this.menuDao.queryList(qo);
                for (MenuBO menu : parentMenuList) {
                    if (Constants.VALID.equals(menu.getValid()) && !menuList.contains(menu)) {
                        menuList.add(menu);
                    }
                }
            }

            MenuPrivilegeBO menuPrivilegeQO = new MenuPrivilegeBO();
            menuPrivilegeQO.setEmployeeId(employeeId);
            List<MenuPrivilegeBO> menuPrivilegeList = this.menuPrivilegeService.queryList(menuPrivilegeQO);
            this.fillPrivilege(menuList, menuPrivilegeList);
            return menuList;
        }
    }
    
    public void fillPrivilege(List<MenuBO> menuList, List<MenuPrivilegeBO> menuPrivilegeList) {
        for (MenuBO menuBO : menuList) {
            for (MenuPrivilegeBO menuPrivilegeBO : menuPrivilegeList) {
                if (menuBO.getId().equals(menuPrivilegeBO.getMenuId())) {
                    menuBO.addPrivilege(menuPrivilegeBO);
                }
            }
        }
    }

    public Set<String> queryPermitUrl(MenuBO bo) {
        if (bo.getEmployeeId() == null || "".equals(bo.getEmployeeId())) {
            return new HashSet<>();
        }

        List<Map<String, Object>> permitUrlList = this.menuDao.queryPermitUrl(bo);
        Set<String> permitUrl = new HashSet<>();
        for (Map<String, Object> data : permitUrlList) {
            if (data == null) {
                continue;
            }
            if (data.get("url") != null && !data.get("url").toString().trim().isEmpty()) {
                permitUrl.add(data.get("url").toString().trim());
            }
            if (data.get("data_sour_url") != null && !data.get("data_sour_url").toString().trim().isEmpty()) {
                String[] sourceUrl = data.get("data_sour_url").toString().split(",");
                for (String url : sourceUrl) {
                    if (url != null && !url.trim().isEmpty()) {
                        permitUrl.add(url.trim());
                    }
                }
            }
            if (data.get("data_dest_url") != null && !data.get("data_dest_url").toString().trim().isEmpty()) {
                permitUrl.add(data.get("data_dest_url").toString().trim());
            }
        }
        return permitUrl;
    }

    public List<MenuBO> queryList(MenuBO bo) {
        return this.menuDao.queryList(bo);
    }

    @WriteTransactional
    public int updateParentId(MenuBO bo) {
        return menuDao.updateParentId(bo);
    }

    @WriteTransactional
    public int updateJson(MenuBO bo) {
        return menuDao.updateJson(bo);
    }
}
